
/* JavaScript content from map/classes/MapCanvas.js in folder common */
define(['dojo', 'map/classes/Utils','map/classes/Poly'], function(dojo, Utils, Poly) {
    return dojo.declare('map.classes.MapCanvas', [], {
      shiftDown: false,
      width: 800,
      height: 600,
      zoomLevel : 0,
      pixelRatio: 1,
      scale : 1.5,
      selectionPoly : null,
      documentEvents: ['onkeydown', 'onkeyup'],
      constructor: function(canvasNode, mapNode, zoomLevel){
        this.canvasNode = canvasNode;
        this.mapNode = mapNode;
        this.context = this.canvasNode.getContext("2d");
        
        this.pixelRatio  = window.devicePixelRatio || this.pixelRatio;        
        $(this.canvasNode).css('zoom', 1/this.pixelRatio );

      },
      init: function(zoomLevel){
        this.resize();
        this.setWinCenter();
        this.updateViewport(zoomLevel);
      },
      resize: function(){
        this.height = this.canvasNode.height = $(this.mapNode).height();
        this.width = this.canvasNode.width = $(this.mapNode).width();
        
        this.context.canvas.width = this.width*this.pixelRatio;
        this.context.canvas.height = this.height*this.pixelRatio;        
        this.context.scale(this.pixelRatio,this.pixelRatio);

        this.win.width = this.canvasNode.width;
        this.win.height = this.canvasNode.height;
        this.win.x = 0;
        this.win.y = 0;
      },      
      calcWinPos :  function () {
        this.win.x = (this.geoToXY(this.win.center.lon, this.win.center.lat)).x - this.win.width / 2;
        this.win.y = (this.geoToXY(this.win.center.lon, this.win.center.lat)).y - this.win.height / 2;
      },
      setWinCenter :  function () {
        var centerX = this.win.x + this.win.width / 2
          , centerY = this.win.y + this.win.height / 2;

        this.win.center = this.xyToGeo(centerX, centerY, true);
      },
      getMapPosition: function(){
        if(typeof this.mapPosition === "undefined" ) {
          var position = $('#contentViewport').position();
          position.top = 138;
          this.mapPosition = position;
        }
        
        return this.mapPosition;
      },
      getEventPageCoords: function(evt) {
        var pageX, pageY;

        if( (evt.originalEvent.pageX !== 0 || evt.originalEvent.pageY !== 0 ) ){          
          pageX = evt.originalEvent.pageX;
          pageY = evt.originalEvent.pageY;
        } 
        else if( typeof evt.originalEvent.touches !== "undefined" && evt.originalEvent.touches.length !== 0 ) {          
          var coords = Array.prototype.pop.call(evt.originalEvent.touches);
          pageX = coords['pageX'];
          pageY = coords['pageY'];
        }

        return {
          'pageX' : pageX,
          'pageY' : pageY
        };
      },
      getMapCoords: function(evt){
        var evtCoords = this.getEventPageCoords(evt)
        , mapPos = this.getMapPosition();

        return {
          mapX : evtCoords.pageX - mapPos.left,
          mapY : evtCoords.pageY - mapPos.top
        };

      },
      documentEventHandlers: {
        onkeydown: function (evt){
          if ((evt.keyCode === 16 || evt.keyCode === 17) && this.shiftDown === false) {
            this.shiftDown = true;
          }
        },
        onkeyup: function (evt){

          if ((evt.keyCode === 16 || evt.keyCode === 17) && this.shiftDown === true) {
            this.shiftDown = false;
          }
        }
      },
      canvasEventHandlers : {
        oncontextmenu : function (evt){ return false; },
        onmousedown: function (evt){
          evt.preventDefault();

          var mapPos, i, collection, pos, coords, mapX, mapY;
          mapPos = this.getMapCoords(evt);

          coords = this.getEventPageCoords(evt);

          if (evt.which === 1 || ( evt.which === 0 && evt.type === "touchstart" )  ) {
            this.last = {
              x: coords.pageX,
              y: coords.pageY
            };

            var selected = document.elementFromPoint(coords.pageX, coords.pageY);

            if (selected) {

              if (this.shiftDown) {

                var geo = this.xyToGeo(mapPos.mapX, mapPos.mapY);
                this.bindEvent('mousemove touchmove', this.canvasEventHandlers['shiftmousemove'] );
                this.bindDocEvent('mouseup touchend', this.canvasEventHandlers['shiftmouseup'] );

              }
              else {              
                
//                console.log("Request check :: ", mapPos.mapX,mapPos.mapY);
                this.trigger('tapSelectCheck', mapPos.mapX, mapPos.mapY );

                this.moving = true;

                this.passthroughEvent(evt);
               
                this.bindEvent('mousemove touchmove', function(evt){ this.passthroughEvent(evt); this.updateViewport(); });

                this.bindDocEvent('mouseup touchend', function(evt){
                  
                  this.unBindEvent('mousemove');
                  this.unBindEvent('touchmove');
                  this.unBindDocEvent('mouseup');
                  this.unBindDocEvent('touchend');


                  this.passthroughEvent(evt);
                });
              }
            }
          }
          if (evt.which === 3) {

          // check to see if we clicked on a car
          // for (i in demo.scenario.cars) {
          //   c = demo.scenario.cars[i];
          //   pos = geoToXY(c.geo);
          //   if (getXYDist({ x: mapX, y: mapY }, pos) < getRadius() && c.id != HELI_ID) {
          //     console.log("selected car " + c.id);
          //     selectCar(c.id);
          //     return;
          //   }
          // }
          // deselectCar();
        }

        return false;
      },
      shiftmousemove: function(evt){
        var mapPos = this.getMapCoords(evt);

        var geo = this.xyToGeo(mapPos.mapX, mapPos.mapY);


        if (!this.selectionPoly || this.selectionPoly.finished) {
           this.selectionPoly = new Poly(this,"selection", [], "BLUE", true, 'GREY');
           this.selectionPoly.finished = false;
        }

        this.selectionPoly.points.push(geo);
      },
      shiftmouseup: function(){

        this.unBindEvent('mousemove touchmove');
        this.unBindDocEvent('mouseup touchend');
        


        if (this.selectionPoly) {
          // for (var i in demo.scenario.cars) {
          //   demo.scenario.cars[i]._confirmed = false;
          // }

          if (this.selectionPoly.isValid()) {
            this.selectionPolyfinished = true;            
            this.trigger('lassoSelectCheck', this.selectionPoly );
            // this.selectionPoly.setColor('BRIGHTGREEN');
            this.selectionPoly = null;
          }
          else
          {
            this.selectionPoly = null; this.markedList = [];
          }
        }
      },
      onmousemove: function(){ return false; },
      mousemove: function(evt){
        evt.preventDefault();
        this.pan(evt.originalEvent.pageX, evt.originalEvent.pageY );
        return false;
      },
      touchmove: function(evt){
        evt.preventDefault();
        this.pan(evt.originalEvent.touches[0].pageX, evt.originalEvent.touches[0].pageY );
        return false;
      },
      mouseup: function(){

        this.unBindEvent('mousemove');
        this.unBindEvent('touchmove');

        this.moving = false;
      }

    },
    passthroughEvent:function(evt){
      
      var passEvt = new $.Event(evt.type)
        , coords = this.getEventPageCoords(evt);

      passEvt.pageX = coords.pageX;
      
      passEvt.pageY = coords.pageY;

      $(this.mapNode).trigger(passEvt);
      
      return false;
    },
    isMarked: function(){

    },   
    setupEvents: function (argument) {

      this.bindEvent('mousedown touchstart', this.canvasEventHandlers['onmousedown'] );
      


    //  this.documentEvents.forEach(function(evtName){
    //   if((typeof this.documentEventHandlers[evtName]) === "function"){
    //     this.bindDocEvent(evtName, this.documentEventHandlers[evtName]);
    //   }
    // }.bind(this));

    },
    unBindDocEvent : function(evtName){
      $(document).off(evtName);
    },
    bindDocEvent: function(evtName,handler){
      if(typeof handler === "function"){
        $(document).on(evtName, handler.bind(this));
      }
    },
    unBindEvent : function(evtName){
      $('#mapCanvas').off(evtName);
    },
    bindEvent : function(evtName, handler){

      if(typeof handler === "function"){

        $('#mapCanvas').on(evtName, handler.bind(this));

      }
    },
    _boundEvents: {},
    on: function(evtName, handler, context){
      context = context || this;
      this._boundEvents[evtName] = [];
      this._boundEvents[evtName].push( { 'handler': handler, 'context' : context });
    },
    trigger : function() {

      var args = Array.prototype.slice.call(arguments);
      var evtName = args.shift();
      if(typeof this._boundEvents[evtName] !== 'object'){
        return false;
      }

      this._boundEvents[evtName].forEach(function(boundEvent){

        boundEvent.handler.apply(boundEvent.context, args);
      });

    },
    win : {
      x: null,
      y: null,
      center: { lon: null, lat: null },
      width: null,
      height: null
    },
    _viewport : {
      lon: {
        min: null,
        max: null
      },
      lat: {
        min: null,
        max: null
      }
    },
    updateViewport: function(zoomLevel) {
      
      this.zoomLevel = zoomLevel;

      this.trigger('updateViewport');
    },
    getMinLon: function() {
      return this._viewport.lon.min;
    },
    getMinLat: function() {
      return this._viewport.lat.min;
    },
    getMaxLon: function() {
      return this._viewport.lon.max;
    },
    getMaxLat: function() {
      return this._viewport.lat.max;
    },
    getLonWidth: function() { return this.getMaxLon() - this.getMinLon(); },
    getLatHeight: function() { return this.getMaxLat() - this.getMinLat(); },
    geoToXY: function(lon, lat, largeOffsetOff) {
      if (!lat) {
        lat = lon.lat;
        lon = lon.lon;
      }
      var xy = {
        x: (parseFloat(lon) - this.getMinLon()) / (this.getMaxLon() - this.getMinLon()) * this.win.width,
        y: this.win.height - ((parseFloat(lat) - this.getMinLat()) / (this.getMaxLat() - this.getMinLat()) * this.win.height)
      };

      return xy;
    },
    getXYDist : function(pt1, pt2) {
      var dist = Math.sqrt(Math.pow(pt2.x - pt1.x, 2) + Math.pow(pt2.y - pt1.y, 2));
      return dist;
    },
    getGeoDist: function(geo1, geo2) {
      var dist = Math.sqrt(Math.pow(geo2.lon - geo1.lon, 2) + Math.pow(geo2.lat - geo1.lat, 2));
      return dist;
    },
    xyToGeo:function(x, y) {
      if (!y) {
        y = x.y;
        x = x.x;
      }

      var geo = {
        lon: this.getMinLon() + (x / this.win.width * this.getLonWidth()),
        lat: this.getMinLat() + ((this.win.height - y) / this.win.height * this.getLatHeight())
      };

      return geo;
    },
    draw : function(){
      // this.drawBackground();
      // this.drawForeground();
    },
    drawBackground:function(){
      this.context.clearRect(0, 0, $(this.canvasNode).width(), $(this.canvasNode).height() );
    },
    drawForeground:function(){

      if(this.selectionPoly !== null ) this.selectionPoly.draw();

    },
    drawActor: function(actor, isConnected) {
      
      var lat = actor.geo.lat
        , lon = actor.geo.lon;

      if (!lon || !lat) { return; }

      if (actor.queue.length > 1) {
        var geoDist = this.getGeoDist(actor.queue[0], actor.queue[1]);
      }
      
      var dispPos = this.geoToXY(lon, lat)
        , dispX = dispPos.x
        , dispY = dispPos.y
        , radius = this.getRadius();

      if (actor.isSelected)

      if (dispX < -5 || dispX > this.width + 5 ||
        dispY < -5 || dispY > this.height + 5) {
        return 0;
      }
      var context = this.context;
      context.lineWidth = 1;
      context.save();
      context.strokeStyle = "#222222";
      if(actor.isSelected && isConnected){
        context.lineWidth = 5;
        context.fillStyle = "#E29045";        
        context.strokeStyle = "#000";
        radius *= 2.25;
      }
      else if (actor.isSelected) {
        context.fillStyle = "rgba(150,245,77,0.8)";
        radius *= 1.25;
      } else if (isConnected) {
        context.fillStyle = "#d41f26";
        radius *= 1.75;
      } else {
        context.fillStyle = actor.color;
        radius *= 0.75;
      }
      context.beginPath();

      if (actor.getDisplayType(this.zoomLevel) === "circle" || (actor.vector.x === 0 && actor.vector.y === 0) ) { 
        if (actor.getDisplayType(this.zoomLevel) === "circle") { 
          context.arc(dispX, dispY, radius, 0, Math.PI*2, true);
        } else {
          context.arc(dispX, dispY, radius / 2, 0, Math.PI*2, true);
        }
      } else {
        var rad = Utils.vectorToRadians(actor.vector);
        if (actor.vector.x < 0) {
          rad += Math.PI;
        }
        var w = radius * this.scale;
        var h = w / 2;
        context.translate(dispX, dispY);
        context.rotate((actor._getHeading() - 90) * Math.PI / 180);
        //var _YELLOW_ = "#ddddaa";
        var displayType = actor.getDisplayType(this.zoomLevel);

        if (displayType === "box") {
          context.fillRect(-w/2, -h/2, w, h);
          context.fillStyle = "#ffffff";
          context.arc(0, 0, 1, 0, Math.PI*2, true);
        } else if (displayType === "car") {
          this.drawCar(context, w, h);
        } else if (displayType === "truck") {
          this.drawTruck(context, w, h);
          //context.arc(0, 0, 1, 0, Math.PI*2, true);
        }
      }
      context.closePath();
      context.stroke();
      context.fill();
      context.restore();

      return 1;
    },
    drawCar: function(context, w, h){
      w *= 0.75;
      context.beginPath();
      context.lineWidth = 1;
      context.strokeStyle = "#222222";
      context.moveTo(-0.5*w, 0.3*w);
      context.lineTo(0.05*w, 0.35*w);
      context.lineTo(0.5*w, 0.2*w);
      context.lineTo(0.5*w, -0.2*w);
      context.lineTo(0.05*w, -0.35*w);
      context.lineTo(-0.5*w, -0.3*w);
      context.closePath();
      context.stroke();
      context.fill();

      context.beginPath();
      context.lineWidth = 1;
      context.fillStyle = "#aaaaaa";
      context.strokeStyle = "#888888";
      context.moveTo(0, 0.20*w);
      context.lineTo(0.3*w, 0.1*w);
      context.lineTo(0.3*w, -0.1*w);
      context.lineTo(0*w, -0.20*w);
      context.closePath();
      context.stroke();
      context.fill();
    },
    drawTruck: function(context, w, h){
      context.lineWidth = 1;
      context.strokeStyle = "#222222";
      context.fillRect(-w/2, -h/2, w, h);
      context.strokeRect(-w/2, -h/2, w, h);
      context.fillRect(w/2, -2/5 * h, w/5, 4/5 * h);
      context.strokeRect(w/2, -2/5 * h, w/5, 4/5 * h);
      context.fillStyle = "#ffffff"; 
    },
    getRadius : function(factor) {
      var styleFactor = 1, power;
      var zoom = this.zoomLevel;

      if (!factor) { factor = 1; }

      if (zoom <= 13) {
        power = 1.2;
      } else if (zoom == 14) {
        power = 1.2;
      } else if (zoom == 15) {
        power = 1.5;
      } else if (zoom == 16) {
        power = 2.0;
      } else if (zoom == 17) {
        power = 3.0;
      }
      if (zoom > 17) {
        power = zoom - 14.5;
      }
      return styleFactor * factor * Math.round(2 * Math.pow(2, power * 0.75));
    }
    
  });

});



